import 'dart:convert';
import 'dart:math';

import 'package:flutter/material.dart';
import 'package:flutter/services.dart' show rootBundle;
import 'package:flutter_map_geojson/flutter_map_geojson.dart';
import 'package:get/get.dart';
import 'package:get_demo/pages/download/domain/entity/DownloadData.dart';
import 'package:file_selector/file_selector.dart';

import '../../../../util/Utils.dart';
import '../../domain/entity/country_bean.dart';
import 'DownloadController.dart';

class MapDataController extends GetxController {
  MapDataController({required this.downloadProvider}) {
    // content = downloadProvider.dataRx;
    initData();
  }
  RxBool visible = false.obs;
  String _province = "", _city = "", _county = "";
  String _provinceName = "", _cityName = "", _countyName = "";

  final DownloadProvider downloadProvider;

  Rx<MapDownloadParams> params = Rx(MapDownloadParams(
      mapUrl:
          "https://server.arcgisonline.com/arcgis/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}.png",
      saveDir: "C:\\MapDownload\\Google Map\\changanqu",
      west: 108.6338137,
      east: 109.2190777,
      north: 34.3060843,
      south: 34.0499605));

  final String TAG = "MapDataController";

  Rx<List<CountryBean>?> countryList = Rx(null);
  Rx<List<DropdownMenuEntry<CountryBean>>?> cityList = Rx(null);
  Rx<List<DropdownMenuEntry<CountryBean>>?> countyList = Rx(null);

  GeoJsonParser geoJsonParser = GeoJsonParser(
    defaultMarkerColor: Colors.red,
    defaultPolygonBorderColor: Colors.red,
    defaultPolygonFillColor: Colors.red.withOpacity(0.1),
    defaultCircleMarkerColor: Colors.red.withOpacity(0.25),
  );

  RxBool loadingData = false.obs;

  openDownloadPage() {
    visible.value = true;
  }

  closePage() {
    visible.value = false;
  }

  bool myFilterFunction(Map<String, dynamic> properties) {
    if (properties['section'].toString().contains('Point M-4')) {
      return false;
    } else {
      return true;
    }
  }

  Future<void> processData() async {
    String data =
        await rootBundle.loadString("assets/area/area_format_array.json");
    print("processData start:${data.length}");
    countryList.value = CountryBean.fromJsonList(data);
    print("processData start:${countryList.value?.length}");
    // parse a small test geoJson
    // normally one would use http to access geojson on web and this is
    // the reason why this funcyion is async.
    // geoJsonParser.parseGeoJsonAsString(data);
  }

  Future<void> _processGeojson(String code) async {
    String name = "assets/area/${code}.geoJson";
    try {
      geoJsonParser.polygons.clear();
      geoJsonParser.markers.clear();
      geoJsonParser.polylines.clear();
      geoJsonParser.circles.clear();
      String data = await rootBundle.loadString(name);
      print("processGeojson start:${name} - ${data.length}");
      geoJsonParser.parseGeoJsonAsString(data);
    } catch (ex) {
      ex.printError();
    }
    // parse a small test geoJson
    // normally one would use http to access geojson on web and this is
    // the reason why this funcyion is async.
  }

  initData() {
    // geoJsonParser.setDefaultMarkerTapCallback(onTapMarkerFunction);
    geoJsonParser.filterFunction = myFilterFunction;
    loadingData.value = true;
    Stopwatch stopwatch2 = Stopwatch()..start();
    processData().then((_) {
      print("processData finish");
      loadingData.value = false;
    });
  }

  //根据省市区县的Code解析本地的经纬度范围文件
  _getCountryGeojson(String code) {
    String newCode = Utils.formatString(code);
    loadingData.value = true;
    _processGeojson(newCode).then((_) {
      print("_getCountryGeojson finish");
      loadingData.value = false;
    });
  }

  //菜单栏选择
  onSelect(String code, String name, int type) {
    switch (type) {
      case 1:
        {
          _province = code;
          _provinceName = name;
          _city = "";
          _cityName = "";
          _county = "";
          _countyName = "";
          cityList.value = buildCityMenuList();
        }
        break;
      case 2:
        {
          _city = code;
          _cityName = name;
          _county = "";
          _countyName = "";
          countyList.value = buildCountyMenuList();
        }
        break;
      case 3:
        {
          _county = code;
          _countyName = name;
        }
        break;
    }
    _getCountryGeojson(code);
  }

  var zoomList = [
    1,
    2,
    3,
    4,
    5,
    6,
    7,
    8,
    9,
    10,
    11,
    12,
    13,
    14,
    15,
    16,
    17,
    18,
    19,
    20,
    21,
    22
  ];
  //选择最小地图级别
  List<DropdownMenuEntry<int>> buildMinList() {
    return zoomList.map((e) {
      return DropdownMenuEntry(label: e.toString(), value: e);
    }).toList();
  }

  //选择最大地图级别
  List<DropdownMenuEntry<int>> buildMaxList() {
    return zoomList.map((e) {
      return DropdownMenuEntry(label: e.toString(), value: e);
    }).toList();
  }

  //选择图片格式
  List<DropdownMenuEntry<String>> buildImageType() {
    return [
      DropdownMenuEntry(value: "jpg", label: "jpg"),
      DropdownMenuEntry(value: "png", label: "png"),
    ];
  }

  //选择路径类型
  List<DropdownMenuEntry<String>> buildPathType() {
    return [
      DropdownMenuEntry(label: "Z/X/Y", value: "{Z}/{X}/{Y}"),
      DropdownMenuEntry(label: "Z/Y/X", value: "{Z}/{Y}/{X}"),
    ];
  }

  //选择省份
  List<DropdownMenuEntry<CountryBean>> buildProviceMenuList() {
    return countryList.value?.map((CountryBean value) {
          return DropdownMenuEntry<CountryBean>(
              value: CountryBean(
                code: value.code,
                name: value.name,
              ),
              label: value.name ?? "");
        })?.toList() ??
        List.empty();
  }

  //选择城市
  List<DropdownMenuEntry<CountryBean>> buildCityMenuList() {
    return countryList.value
            ?.firstWhereOrNull((CountryBean value) => value.code == _province)
            ?.children
            ?.map((CountryBean value) {
          return DropdownMenuEntry<CountryBean>(
              value: CountryBean(
                code: value.code,
                name: value.name,
              ),
              label: value.name ?? "");
        }).toList() ??
        List.empty();
  }

  //选择县
  List<DropdownMenuEntry<CountryBean>> buildCountyMenuList() {
    return countryList.value
            ?.firstWhereOrNull((CountryBean value) => value.code == _province)
            ?.children
            ?.firstWhereOrNull((CountryBean value) => value.code == _city)
            ?.children
            ?.map((CountryBean value) {
          return DropdownMenuEntry<CountryBean>(
              value: CountryBean(
                code: value.code,
                name: value.name,
              ),
              label: value.name ?? "");
        })?.toList() ??
        List.empty();
  }

  void selectDir() async {
    final String? path =
        await getDirectoryPath(initialDirectory: params.value.saveDir);
    if (path != null) {
      print("selectDir:$path");
      params.value.setSaveUrl(path);
      params.refresh();
    }
  }

  // Rx<DownloadData?> content = Rx(null);

  void startDownload(MapDownloadParams params) async {
    bool isSuc = _checkParams(params);
    if (!isSuc) {
      return;
    }
    this.params.value = params;
    List<LayerBean> list = generateData();
    try {
      ///获取 Token
      // RootIsolateToken rootIsolateToken = RootIsolateToken.instance!;
      // await compute(downloadProvider.startMapDownloadTask,
      //     (params, list, rootIsolateToken));

      downloadProvider.startMapDownloadTask((params, list)).then(
          (value) => _onTaskError(value));
    } catch (e) {
      e.printInfo();
      // downloadProvider.stopMapDownloadTask();
    }
  }

  void stopMapDownloadTask() {
    downloadProvider.stopMapDownloadTask();
  }

  Rx<DownloadData?> getData() {
    return downloadProvider.dataRx;
  }

  void puaseTask() {
    downloadProvider.puaseTask();
  }

  void resumeTask() {
    String res = downloadProvider.resumeTask();
    _onTaskError(res);
  }

  void _onTaskError(final String message) {
    if (message.isEmpty) {
      return;
    }
    Get.snackbar(
      'title',
      "message",
      mainButton: TextButton(onPressed: () {}, child: Text(message)),
      isDismissible: true,
      duration: Duration(seconds: 5),
      snackbarStatus: (status) => print(status),
    );
  }

  /**校验用户输入参数 */
  bool _checkParams(MapDownloadParams params) {
    return true;
  }

  List<LayerBean> generateData() {
    if (params == null) {
      return [];
    }
    int minZoom = params.value.minZoom;
    int maxZoom = params.value.maxZoom;
    double north = params.value.north;
    double south = params.value.south;
    double west = params.value.west;
    double east = params.value.east;
    List<LayerBean> _layers = [];
    for (int zoom = minZoom; zoom <= maxZoom; zoom++) {
      Offset westNorth = latLngToPixel(north, west, zoom);
      Offset eastSouth = latLngToPixel(south, east, zoom);
      print("z:$zoom x in[${westNorth.dx.toInt()},${eastSouth.dx.toInt()}]" +
          "  y in[${westNorth.dy.toInt()},${eastSouth.dy.toInt()}]");
      _layers.add(LayerBean(
          zoom: zoom,
          minX: westNorth.dx.toInt(),
          maxX: eastSouth.dx.toInt(),
          minY: westNorth.dy.toInt(),
          maxY: eastSouth.dy.toInt()));
    }
    return _layers;
  }

  Offset latLngToPixel(double lat, double lng, int zoom) {
    double x = (lng + 180) / 360 * (1 << zoom);
    double y = (1 - log(tan(lat * pi / 180) + 1 / cos(lat * pi / 180)) / pi) /
        2 *
        (1 << zoom);
    return Offset(x, y);
  }

  Offset pixelToTile(Offset pixel) {
    int tileX = pixel.dx ~/ 256; // 256是瓦片的宽度和高度
    int tileY = pixel.dy ~/ 256;
    return Offset(tileX.toDouble(), tileY.toDouble());
  }
}

class MapDownloadParams {
  final String mapUrl; //瓦片源地址
  String saveDir; //瓦片保存路径
  final String? mapName; //瓦片源名称
  final double west; //下载区域 西 经度
  final double east; //下载区域 东 经度
  final double north; //下载区域 北纬度
  final double south; //下载区域 南纬度
  final int maxThread; //下载最大并发线程数
  final int maxZoom; //最小层级
  final int minZoom; //最大层级
  String imageType;

  MapDownloadParams(
      {required this.mapUrl,
      required this.saveDir,
      required this.west,
      required this.east,
      required this.north,
      required this.south,
      this.imageType = "jpg",
      this.minZoom = 1,
      this.maxZoom = 18,
      this.mapName = "",
      this.maxThread = 5}) {}

  setSaveUrl(String path) {
    this.saveDir = path;
  }

  setImageType(String type) {
    this.imageType = type;
  }
}

class LayerBean {
  final int zoom;
  final int minX;
  final int maxX;
  final int minY;
  final int maxY;

  LayerBean(
      {required this.zoom,
      required this.minX,
      required this.maxX,
      required this.minY,
      required this.maxY});
}
